package com.tally.project.system.billing.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.tally.common.enums.WeekEnum;
import com.tally.common.utils.DateUtils;
import com.tally.common.utils.text.Convert;
import com.tally.framework.security.utils.SecurityUtils;
import com.tally.project.system.billing.domain.Billing;
import com.tally.project.system.billing.domain.vo.BillingDayVo;
import com.tally.project.system.billing.domain.vo.BillingMonthVo;
import com.tally.project.system.billing.domain.vo.BillingStatisticVo;
import com.tally.project.system.billing.domain.vo.BillingVo;
import com.tally.project.system.billing.mapper.BillingMapper;
import com.tally.project.system.billing.service.IBillingService;
import com.tally.project.system.category.domain.Category;
import com.tally.project.system.category.service.ICategoryService;
import com.tally.project.system.user.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 账目流水信息Service业务层处理
 * @author soul
 * @date 2023-05-14
 */
@Service
public class BillingServiceImpl implements IBillingService
{
    @Autowired
    private BillingMapper billingMapper;

    @Autowired
    private ICategoryService iCategoryService;

    /**
     * 查询账目流水信息
     * 
     * @param id 账目流水信息主键
     * @return 账目流水信息
     */
    @Override
    public BillingVo selectBillingById(Long id)
    {
        Billing billing = billingMapper.selectBillingById(id);
        // 查询账单分类
        List<Category> categories = iCategoryService.selectCategoryList(new Category());
        // 账单分类
        Map<Long, Category> categoryMap = categories.stream().collect(Collectors.toMap(Category::getId, GiftBag -> GiftBag));
        return new BillingVo(billing, categoryMap);
    }

    /**
     * 查询账目流水信息列表
     * 
     * @param billing 账目流水信息
     * @return 账目流水信息
     */
    @Override
    public BillingMonthVo selectBillingList(Billing billing) {
        User user = SecurityUtils.getUser();
        // 设置用户ID
        billing.setUserId(user.getUserId());
        // 设置账本ID
        billing.setBookId(user.getBookId());
        // 获取账单
        List<Billing> billings = billingMapper.selectBillingList(billing);
        if (billings.size() <= 0){
            return new BillingMonthVo();
        }
        // 查询账单分类
        List<Category> categories = iCategoryService.selectCategoryList(new Category());
        // 账单分类
        Map<Long, Category> categoryMap = categories.stream().collect(Collectors.toMap(Category::getId, GiftBag -> GiftBag));

        // 按天分组
        Map<Integer, List<Billing>> listMap = billings.stream().collect(Collectors.groupingBy(Billing::getDay));

        // 每月账单集合
        BillingMonthVo billingMonthVo = new BillingMonthVo();
        // 每天账单集合
        List<BillingDayVo> billingDayVoList = new ArrayList<>();

        for (Map.Entry<Integer, List<Billing>> entry : listMap.entrySet()) {
            // 每日账单实体类
            BillingDayVo billingDayVo = new BillingDayVo();
            // 设置日
            billingDayVo.setDay(entry.getKey());
            // 每日账单
            List<Billing> entryValue = entry.getValue();
            // 获取当前日
            Billing billingDay = entryValue.get(0);
            // 每日账单归时间
            billingDayVo.setDate(billingDay.getDate().format(DateTimeFormatter.ofPattern("MM月dd日")));
            // 每日账单归属周
            billingDayVo.setWeek(billingDay.getWeek());
            //计算一天的总收入和总支出
            billingDayVo.setIn(BigDecimal.ZERO);
            billingDayVo.setOut(BigDecimal.ZERO);

            entryValue.forEach(value -> {
                // 计算总支出和总收入
                if (value.getType() == 0) {
                    BigDecimal add = billingDayVo.getIn().add(value.getAmount());
                    billingDayVo.setIn(add);
                } else {
                    BigDecimal add = billingDayVo.getOut().add(value.getAmount());
                    billingDayVo.setOut(add);
                }
            });
            List<BillingVo> objects = new ArrayList<>();

            for (Billing object : entryValue) {
                objects.add(new BillingVo(object, categoryMap));
            }
            // 设置并放入List中
            billingDayVo.setList(objects);
            billingDayVoList.add(billingDayVo);
        }

        // 每个月收入
        billingMonthVo.setIn(BigDecimal.ZERO);
        // 每个月支出
        billingMonthVo.setOut(BigDecimal.ZERO);

        // 进行计算
        billingDayVoList.forEach(billingDayVo -> {
            BigDecimal addIn = billingMonthVo.getIn().add(billingDayVo.getIn());
            BigDecimal addOut = billingMonthVo.getOut().add(billingDayVo.getOut());
            billingMonthVo.setIn(addIn);
            billingMonthVo.setOut(addOut);
        });

        // 根据天数倒序排序
        billingDayVoList = billingDayVoList.stream().sorted(Comparator.comparing(BillingDayVo::getDay).reversed()).collect(Collectors.toList());
        // 消费列表
        billingMonthVo.setList(billingDayVoList);

        return billingMonthVo;
    }

    /**
     * 账单统计
     * @param billing
     * @return
     */
    @Override
    public List<BillingStatisticVo> selectBillingStatisticList(Billing billing) {
        User user = SecurityUtils.getUser();
        // 设置用户ID
        billing.setUserId(user.getUserId());
        // 设置账本ID
        billing.setBookId(user.getBookId());
        return billingMapper.selectBillingStatisticList(billing);
    }

    /**
     * 新增账目流水信息
     * 
     * @param billing 账目流水信息
     * @return 结果
     */
    @Override
    public int insertBilling(Billing billing)
    {
        LocalDateTime cashTime = LocalDateTime.ofEpochSecond(billing.getTimestamp() / 1000, 0, ZoneOffset.ofHours(8));
        // 消费时间
        billing.setDate(cashTime);
        // 2、计算日期年、月、日、周数
        int weekValue = cashTime.getDayOfWeek().getValue();
        // 周
        billing.setWeek(WeekEnum.getValue(weekValue));
        // 年
        billing.setYear(cashTime.getYear());
        // 月
        billing.setMonth(cashTime.getMonthValue());
        // 日
        billing.setDay(cashTime.getDayOfMonth());
        // 当前用户信息
        User user = SecurityUtils.getUser();
        // 设置用户ID
        billing.setUserId(user.getUserId());
        // 设置账本ID
        billing.setBookId(user.getBookId());
        // 创建时间
        billing.setCreateTime(DateUtils.getNowDate());
        return billingMapper.insertBilling(billing);
    }

    /**
     * 修改账目流水信息
     * 
     * @param billing 账目流水信息
     * @return 结果
     */
    @Override
    public int updateBilling(Billing billing)
    {
        LocalDateTime cashTime = LocalDateTime.ofEpochSecond(billing.getTimestamp() / 1000, 0, ZoneOffset.ofHours(8));
        // 消费时间
        billing.setDate(cashTime);
        // 2、计算日期年、月、日、周数
        int weekValue = cashTime.getDayOfWeek().getValue();
        // 周
        billing.setWeek(WeekEnum.getValue(weekValue));
        // 年
        billing.setYear(cashTime.getYear());
        // 月
        billing.setMonth(cashTime.getMonthValue());
        // 日
        billing.setDay(cashTime.getDayOfMonth());
        // 当前用户信息
        User user = SecurityUtils.getUser();
        // 设置用户ID
        billing.setUserId(user.getUserId());
        // 设置账本ID
        billing.setBookId(user.getBookId());
        // 更改时间
        billing.setUpdateTime(DateUtils.getNowDate());
        return billingMapper.updateBilling(billing);
    }

    /**
     * 批量删除账目流水信息
     * @param ids 需要删除的账目流水信息主键
     * @return 结果
     */
    @Override
    public int deleteBillingByIds(String ids)
    {
        return billingMapper.deleteBillingByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除账目流水信息信息
     * 
     * @param id 账目流水信息主键
     * @return 结果
     */
    @Override
    public int deleteBillingById(Long id)
    {
        return billingMapper.deleteBillingById(id);
    }
}
